<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha256-CTSx/A06dm1B063156EVh15m6Y67pAjZZaQc89LLSrU=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.24/fancybox/fancybox.css" integrity="sha256-vQkngPS8jiHHH0I6ABTZroZk8NPZ7b+MUReOFE9UsXQ=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"rjyblog.gitee.io","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.18.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":null},"fold":{"enable":false,"height":500},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="Android消息循环">
<meta property="og:type" content="article">
<meta property="og:title" content="Handler源码解析">
<meta property="og:url" content="https://rjyblog.gitee.io/posts/48a4fa29.html">
<meta property="og:site_name" content="任建勇的博客">
<meta property="og:description" content="Android消息循环">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2023-09-05T00:38:01.000Z">
<meta property="article:modified_time" content="2023-12-15T03:54:37.523Z">
<meta property="article:author" content="Jason">
<meta property="article:tag" content="Android">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="https://rjyblog.gitee.io/posts/48a4fa29.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://rjyblog.gitee.io/posts/48a4fa29.html","path":"posts/48a4fa29.html","title":"Handler源码解析"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Handler源码解析 | 任建勇的博客</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">任建勇的博客</p>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E5%90%AF%E5%8A%A8%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97"><span class="nav-text">当前线程启动消息队列</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96Looper-prepare"><span class="nav-text">初始化Looper.prepare()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%9B%E5%BB%BAHandler"><span class="nav-text">创建Handler</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%90%AF%E5%8A%A8%E6%B6%88%E6%81%AF%E5%BE%AA%E7%8E%AF"><span class="nav-text">启动消息循环</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81-Handler-post"><span class="nav-text">消息发送 Handler.post()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BB%8E%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E8%8E%B7%E5%8F%96%E6%B6%88%E6%81%AF"><span class="nav-text">从消息队列获取消息</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#IdleHandler"><span class="nav-text">IdleHandler</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%B6%88%E6%81%AF%E9%98%BB%E5%A1%9E%E7%AD%89%E5%BE%85%E7%9A%84%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0"><span class="nav-text">消息阻塞等待的底层实现</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%90%8C%E6%AD%A5%E5%B1%8F%E9%9A%9C"><span class="nav-text">同步屏障</span></a></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Jason"
      src="/images/avatar.png">
  <p class="site-author-name" itemprop="name">Jason</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">66</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">13</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">23</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://rjyblog.gitee.io/posts/48a4fa29.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.png">
      <meta itemprop="name" content="Jason">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="任建勇的博客">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="Handler源码解析 | 任建勇的博客">
      <meta itemprop="description" content="Android消息循环">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Handler源码解析
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-09-05 08:38:01" itemprop="dateCreated datePublished" datetime="2023-09-05T08:38:01+08:00">2023-09-05</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-12-15 11:54:37" itemprop="dateModified" datetime="2023-12-15T11:54:37+08:00">2023-12-15</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Android/" itemprop="url" rel="index"><span itemprop="name">Android</span></a>
        </span>
    </span>

  
</div>

            <div class="post-description">Android消息循环</div>
        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><h2 id="当前线程启动消息队列"><a href="#当前线程启动消息队列" class="headerlink" title="当前线程启动消息队列"></a>当前线程启动消息队列</h2><p>Thread默认是没有消息循环机制的，而Looper就是在Thread基础上运行一个消息循环，通过<code>Looper.prepare()</code>可以把当前线程初始化为一个<strong>Looper thread</strong>。一个典型的Looper thread创建示例如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LooperThread</span> <span class="keyword">extends</span> <span class="title class_">Thread</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> Handler mHandler;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">        Looper.prepare();</span><br><span class="line">        mHandler = <span class="keyword">new</span> <span class="title class_">Handler</span>(Looper.myLooper()) &#123;</span><br><span class="line">            <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">handleMessage</span><span class="params">(Message msg)</span> &#123;</span><br><span class="line">                <span class="comment">//在此处理消息</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        Looper.loop();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上述代码分为三部：1）调用Looper.prepare()初始化Looper；2）创建一个Handler用于与Looper进行交互；3）调用Looper.loop()启动消息循环。下面分别看下这三步是如何实现的：</p>
<h3 id="初始化Looper-prepare"><a href="#初始化Looper-prepare" class="headerlink" title="初始化Looper.prepare()"></a>初始化Looper.prepare()</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//android-12.1.0_r27\frameworks\base\core\java\android\os\Looper.java</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> ThreadLocal&lt;Looper&gt; sThreadLocal = <span class="keyword">new</span> <span class="title class_">ThreadLocal</span>&lt;Looper&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">prepare</span><span class="params">()</span> &#123; <span class="comment">//prepare是静态方法</span></span><br><span class="line">        prepare(<span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">prepare</span><span class="params">(<span class="type">boolean</span> quitAllowed)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (sThreadLocal.get() != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">//一个线程中Looper.prepare()只能执行一次，否则会抛出异常</span></span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">&quot;Only one Looper may be created per thread&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//构造了一个Looper放到ThreadLocal中</span></span><br><span class="line">        sThreadLocal.set(<span class="keyword">new</span> <span class="title class_">Looper</span>(quitAllowed));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//Looper的构造方法也很简单：1）创建消息队列；2）获取当先线程句柄；</span></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Looper</span><span class="params">(<span class="type">boolean</span> quitAllowed)</span> &#123;</span><br><span class="line">        mQueue = <span class="keyword">new</span> <span class="title class_">MessageQueue</span>(quitAllowed);</span><br><span class="line">        mThread = Thread.currentThread();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h3 id="创建Handler"><a href="#创建Handler" class="headerlink" title="创建Handler"></a>创建Handler</h3><p>用户无法直接使用Looper来进行消息发送和处理，而是需要通过一个Handler来实现。使用Handler可以发送和处理Message，或者运行一个Runnable。每个Handler都会绑定一个Looper，Handler将会把message和runnable投递到Looper的消息队列中，然后Looper thread将会执行这些message和runnable。</p>
<p>下图是Handler与Looper、Thread、MessageQueue之间的对应关系，Thread和Looper是一对一的关系，否则会抛出异常，一个Looper只有一个消息队列，但是可以多个Handler对应同一个Looper。</p>
<?xml version="1.0" encoding="us-ascii" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="243px" preserveAspectRatio="none" style="width:388px;height:243px;background:#FFFFFF;" version="1.1" viewBox="0 0 388 243" width="388px" zoomAndPan="magnify"><defs/><g><!--entity Looper--><g id="elem_Looper"><rect fill="#F1F1F1" height="36.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="71" x="220" y="104"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="51" x="230" y="126.9951">Looper</text></g><!--entity Thread--><g id="elem_Thread"><rect fill="#F1F1F1" height="36.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="70" x="221.5" y="201"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="50" x="231.5" y="223.9951">Thread</text></g><!--entity MessageQueue--><g id="elem_MessageQueue"><rect fill="#F1F1F1" height="36.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="126" x="60.5" y="201"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="106" x="70.5" y="223.9951">MessageQueue</text></g><!--entity Handler1--><g id="elem_Handler1"><rect fill="#F1F1F1" height="36.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="84" x="137.5" y="7"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="64" x="147.5" y="29.9951">Handler1</text></g><!--entity Handler2--><g id="elem_Handler2"><rect fill="#F1F1F1" height="36.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="83" x="7" y="7"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="63" x="17" y="29.9951">Handler2</text></g><!--entity Handler3--><g id="elem_Handler3"><rect fill="#F1F1F1" height="36.2969" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="84" x="269.5" y="7"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="64" x="279.5" y="29.9951">Handler3</text></g><!--reverse link Looper to Thread--><g id="link_Looper_Thread"><path d="M255.8097,152.4238 C255.9907,169.5648 256.138,183.5832 256.318,200.686 " fill="none" id="Looper-backto-Thread" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="255.683,140.4245,251.7466,146.4664,255.8097,152.4238,259.7461,146.3819,255.683,140.4245" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link Looper to MessageQueue--><g id="link_Looper_MessageQueue"><path d="M221.8562,147.2135 C197.9332,164.4307 171.086,183.7524 147.226,200.9242 " fill="none" id="Looper-backto-MessageQueue" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="231.596,140.2038,224.3895,140.462,221.8562,147.2135,229.0626,146.9553,231.596,140.2038" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link Handler1 to Looper--><g id="link_Handler1_Looper"><path d="M200.9358,52.7949 C214.6478,69.9369 227.967,86.583 241.649,103.686 " fill="none" id="Handler1-backto-Looper" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="193.44,43.424,194.0643,50.608,200.9358,52.7949,200.3115,45.6108,193.44,43.424" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link Handler2 to Looper--><g id="link_Handler2_Looper"><path d="M96.8924,48.2092 C134.8743,65.6402 182.305,87.408 219.678,104.56 " fill="none" id="Handler2-backto-Looper" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="85.9861,43.204,89.7708,49.3421,96.8924,48.2092,93.1077,42.0712,85.9861,43.204" style="stroke:#181818;stroke-width:1.0;"/></g><!--reverse link Handler3 to Looper--><g id="link_Handler3_Looper"><path d="M295.1356,53.7618 C285.0316,70.9038 275.788,86.583 265.706,103.686 " fill="none" id="Handler3-backto-Looper" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="301.229,43.424,294.7364,46.5618,295.1356,53.7618,301.6282,50.624,301.229,43.424" style="stroke:#181818;stroke-width:1.0;"/></g><!--link Handler1 to MessageQueue--><g id="link_Handler1_MessageQueue"><path d="M169.356,43.044 C160.642,58.449 148.42,82.017 141.5,104 C131.032,137.2554 126.9642,171.9891 125.1212,194.6595 " fill="none" id="Handler1-to-MessageQueue" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:1.0,3.0;"/><polygon fill="#181818" points="124.635,200.6398,129.3511,191.9935,125.0401,195.6562,121.3774,191.3453,124.635,200.6398" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="59" x="142.5" y="126.5669">message</text></g><!--link Handler2 to MessageQueue--><g id="link_Handler2_MessageQueue"><path d="M48.264,43.315 C48.5367,66.287 51.0893,107.698 64.5,140 C74.2007,163.3655 88.5232,181.5495 102.2059,196.3513 " fill="none" id="Handler2-to-MessageQueue" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:1.0,3.0;"/><polygon fill="#181818" points="106.2787,200.7572,103.1068,191.4331,102.8847,197.0856,97.2322,196.8635,106.2787,200.7572" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="59" x="65.5" y="126.5669">message</text></g><!--link Handler3 to MessageQueue--><g id="link_Handler3_MessageQueue"><path d="M316.368,43.194 C322.059,67.15 328.371,110.895 308.5,140 C293.465,162.0218 236.0385,183.7624 187.6605,199.1559 " fill="none" id="Handler3-to-MessageQueue" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:1.0,3.0;"/><polygon fill="#181818" points="181.943,200.9752,191.7322,202.058,186.7076,199.4591,189.3065,194.4346,181.943,200.9752" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="59" x="321.5" y="126.5669">message</text></g><!--SRC=[AyxEp2j8B4hCLKZEpot8pqlDAmakgSn9LIXAJIv9p4lFIUMAzidFBqWjYbNGqjLLY0x9A4fDJ8b54_LDBIvEJ4yDB4qjJGNAUIJcfUIa5Xb2PQ5AuU96ECIDSOW3pT6DJialAKbDYTMrGxDDmKeX5y97DfyazSR4gGS0]--></g></svg>

<p>下面看下Handler的构造函数：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">    <span class="keyword">public</span> <span class="title function_">Handler</span><span class="params">(<span class="meta">@Nullable</span> Callback callback, <span class="type">boolean</span> async)</span> &#123;</span><br><span class="line">        ...... <span class="comment">//代码省略</span></span><br><span class="line">        mLooper = Looper.myLooper(); <span class="comment">//默认使用当前线程关联的looper，也可以通过其他构造函数来指定使用哪个Looper</span></span><br><span class="line">        <span class="keyword">if</span> (mLooper == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(</span><br><span class="line">                <span class="string">&quot;Can&#x27;t create handler inside thread &quot;</span> + Thread.currentThread()</span><br><span class="line">                        + <span class="string">&quot; that has not called Looper.prepare()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        mQueue = mLooper.mQueue; <span class="comment">//获取Looper的消息队列</span></span><br><span class="line">        mCallback = callback;</span><br><span class="line">        mAsynchronous = async;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">//android-12.1.0_r27\frameworks\base\core\java\android\os\Looper.java</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="meta">@Nullable</span> Looper <span class="title function_">myLooper</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> sThreadLocal.get(); <span class="comment">//从ThreadLocal中获取当前线程关联的Looper</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h3 id="启动消息循环"><a href="#启动消息循环" class="headerlink" title="启动消息循环"></a>启动消息循环</h3><p>下面代码是一个精简版代码，精简了debug、异常处理等相关逻辑，但基本逻辑不变。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">loop</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="type">Looper</span> <span class="variable">me</span> <span class="operator">=</span> myLooper();</span><br><span class="line">        me.mInLoop = <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">for</span> (;;) &#123; <span class="comment">//forever loop</span></span><br><span class="line">            <span class="keyword">if</span> (!loopOnce(me, ident, thresholdOverride)) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Poll and deliver single message, return true if the outer loop should continue.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">loopOnce</span><span class="params">(<span class="keyword">final</span> Looper me, <span class="keyword">final</span> <span class="type">long</span> ident, <span class="keyword">final</span> <span class="type">int</span> thresholdOverride)</span> &#123;</span><br><span class="line">        <span class="type">Message</span> <span class="variable">msg</span> <span class="operator">=</span> me.mQueue.next(); <span class="comment">// 从消息队列中读取消息，如果消息队列为空将会堵塞等待</span></span><br><span class="line">        <span class="keyword">if</span> (msg == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// No message indicates that the message queue is quitting.</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">Object</span> <span class="variable">token</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//msg.target就是Handler，调用Handler.dispatchMessage进行消息处理</span></span><br><span class="line">            msg.target.dispatchMessage(msg);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception exception) &#123;</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        msg.recycleUnchecked();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">//android-12.1.0_r27\frameworks\base\core\java\android\os\Handler.java</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">dispatchMessage</span><span class="params">(<span class="meta">@NonNull</span> Message msg)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (msg.callback != <span class="literal">null</span>) &#123; <span class="comment">//callback就是Runnable</span></span><br><span class="line">            handleCallback(msg); <span class="comment">//执行Runnable.run()</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (mCallback != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (mCallback.handleMessage(msg)) &#123;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            handleMessage(msg); <span class="comment">//处理message消息</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="消息发送-Handler-post"><a href="#消息发送-Handler-post" class="headerlink" title="消息发送 Handler.post()"></a>消息发送 Handler.post()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//android-12.1.0_r27\frameworks\base\core\java\android\os\Handler.java</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">post</span><span class="params">(<span class="meta">@NonNull</span> Runnable r)</span> &#123;</span><br><span class="line">        <span class="comment">//1. 通过getPostMessage将Runnable转换为Message，然后调用sendMessageDelayed</span></span><br><span class="line">        <span class="keyword">return</span> sendMessageDelayed(getPostMessage(r), <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Message <span class="title function_">getPostMessage</span><span class="params">(Runnable r)</span> &#123;</span><br><span class="line">        <span class="type">Message</span> <span class="variable">m</span> <span class="operator">=</span> Message.obtain(); <span class="comment">//从消息池中获取一个消息，是为了消息的复用，避免重新new一个类</span></span><br><span class="line">        m.callback = r;</span><br><span class="line">        <span class="keyword">return</span> m;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p>上述代码通过post执行一个Runnable，通过getPostMessage把Runnable转换为Message，然后调用sendMessageDelayed：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">sendMessageDelayed</span><span class="params">(<span class="meta">@NonNull</span> Message msg, <span class="type">long</span> delayMillis)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (delayMillis &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        delayMillis = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//获取当前系统时间，加上延时时间就是消息被执行的时间，然后调用sendMessageAtTime</span></span><br><span class="line">    <span class="keyword">return</span> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">sendMessageAtTime</span><span class="params">(<span class="meta">@NonNull</span> Message msg, <span class="type">long</span> uptimeMillis)</span> &#123;</span><br><span class="line">    <span class="type">MessageQueue</span> <span class="variable">queue</span> <span class="operator">=</span> mQueue;</span><br><span class="line">    ......</span><br><span class="line">    <span class="keyword">return</span> enqueueMessage(queue, msg, uptimeMillis);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">enqueueMessage</span><span class="params">(<span class="meta">@NonNull</span> MessageQueue queue, <span class="meta">@NonNull</span> Message msg,</span></span><br><span class="line"><span class="params">        <span class="type">long</span> uptimeMillis)</span> &#123;</span><br><span class="line">    msg.target = <span class="built_in">this</span>; <span class="comment">//Message的target字段指向Handler自身，target就是消息的最终投递目的地</span></span><br><span class="line">    msg.workSourceUid = ThreadLocalWorkSource.getUid();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (mAsynchronous) &#123;</span><br><span class="line">        msg.setAsynchronous(<span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//消息插入队列，并指定消息投递时间</span></span><br><span class="line">    <span class="keyword">return</span> queue.enqueueMessage(msg, uptimeMillis);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>通过Handler的post来执行任务最终会被加入到Looper的消息队列中，即MessageQueue：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//android-12.1.0_r27\frameworks\base\core\java\android\os\MessageQueue.java</span></span><br><span class="line"><span class="comment">// MessageQueue通过一个单项链表维护Message</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">enqueueMessage</span><span class="params">(Message msg, <span class="type">long</span> when)</span> &#123;</span><br><span class="line">        ...... <span class="comment">//代码省略</span></span><br><span class="line">        <span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">            ......</span><br><span class="line">            msg.markInUse();</span><br><span class="line">            msg.when = when;</span><br><span class="line">            <span class="type">Message</span> <span class="variable">p</span> <span class="operator">=</span> mMessages;</span><br><span class="line">            <span class="type">boolean</span> needWake;</span><br><span class="line">            <span class="keyword">if</span> (p == <span class="literal">null</span> || when == <span class="number">0</span> || when &lt; p.when) &#123;</span><br><span class="line">                <span class="comment">//队列为空，或者队列中的消息投递时间比新消息晚，就会把新消息放在队首。</span></span><br><span class="line">                msg.next = p;</span><br><span class="line">                mMessages = msg;</span><br><span class="line">                needWake = mBlocked;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                needWake = mBlocked &amp;&amp; p.target == <span class="literal">null</span> &amp;&amp; msg.isAsynchronous();</span><br><span class="line">                Message prev;</span><br><span class="line">                <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">                    prev = p;</span><br><span class="line">                    p = p.next;</span><br><span class="line">                    <span class="keyword">if</span> (p == <span class="literal">null</span> || when &lt; p.when) &#123; <span class="comment">//按照投递时间先后进行排序插入</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">if</span> (needWake &amp;&amp; p.isAsynchronous()) &#123;</span><br><span class="line">                        needWake = <span class="literal">false</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                msg.next = p;</span><br><span class="line">                prev.next = msg;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (needWake) &#123; <span class="comment">//判断是否需要唤醒线程</span></span><br><span class="line">                nativeWake(mPtr);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<p><code>nativeWake</code>的源码：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//android-12.1.0_r27\frameworks\base\core\jni\android_os_MessageQueue.cpp</span></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">android_os_MessageQueue_nativeWake</span><span class="params">(JNIEnv* env, jclass clazz, jlong ptr)</span> </span>&#123;</span><br><span class="line">    NativeMessageQueue* nativeMessageQueue = <span class="built_in">reinterpret_cast</span>&lt;NativeMessageQueue*&gt;(ptr);</span><br><span class="line">    nativeMessageQueue-&gt;<span class="built_in">wake</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">NativeMessageQueue::wake</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    mLooper-&gt;<span class="built_in">wake</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//android-12.1.0_r27\system\core\libutils\Looper.cpp</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Looper::wake</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> DEBUG_POLL_AND_WAKE</span></span><br><span class="line">    <span class="built_in">ALOGD</span>(<span class="string">&quot;%p ~ wake&quot;</span>, <span class="keyword">this</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    <span class="type">uint64_t</span> inc = <span class="number">1</span>;</span><br><span class="line">    <span class="type">ssize_t</span> nWrite = <span class="built_in">TEMP_FAILURE_RETRY</span>(<span class="built_in">write</span>(mWakeEventFd.<span class="built_in">get</span>(), &amp;inc, <span class="built_in">sizeof</span>(<span class="type">uint64_t</span>)));</span><br><span class="line">    <span class="keyword">if</span> (nWrite != <span class="built_in">sizeof</span>(<span class="type">uint64_t</span>)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (errno != EAGAIN) &#123;</span><br><span class="line">            <span class="built_in">LOG_ALWAYS_FATAL</span>(<span class="string">&quot;Could not write wake signal to fd %d (returned %zd): %s&quot;</span>,</span><br><span class="line">                             mWakeEventFd.<span class="built_in">get</span>(), nWrite, <span class="built_in">strerror</span>(errno));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="从消息队列获取消息"><a href="#从消息队列获取消息" class="headerlink" title="从消息队列获取消息"></a>从消息队列获取消息</h2><p>Looper.loop()会通过MessageQueue.next()不断从消息队列获取消息，如果队列为空，线程就会阻塞等待。下面是next()对应的源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br></pre></td><td class="code"><pre><span class="line">Message <span class="title function_">next</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// Return here if the message loop has already quit and been disposed.</span></span><br><span class="line">    <span class="comment">// This can happen if the application tries to restart a looper after quit</span></span><br><span class="line">    <span class="comment">// which is not supported.</span></span><br><span class="line">    <span class="keyword">final</span> <span class="type">long</span> <span class="variable">ptr</span> <span class="operator">=</span> mPtr; <span class="comment">//mPtr是一个long类型，是native层c++类NativeMessageQueue对象的指针</span></span><br><span class="line">    <span class="keyword">if</span> (ptr == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> <span class="variable">pendingIdleHandlerCount</span> <span class="operator">=</span> -<span class="number">1</span>; <span class="comment">// -1 only during first iteration</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">nextPollTimeoutMillis</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">        <span class="keyword">if</span> (nextPollTimeoutMillis != <span class="number">0</span>) &#123;</span><br><span class="line">            Binder.flushPendingCommands();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        nativePollOnce(ptr, nextPollTimeoutMillis); <span class="comment">//阻塞等待，第二个参数是超时时间</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="type">long</span> <span class="variable">now</span> <span class="operator">=</span> SystemClock.uptimeMillis();</span><br><span class="line">            <span class="type">Message</span> <span class="variable">prevMsg</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">            <span class="type">Message</span> <span class="variable">msg</span> <span class="operator">=</span> mMessages; <span class="comment">//mMessages是个单项链表，这里是获取链表首位的Message</span></span><br><span class="line">            <span class="keyword">if</span> (msg != <span class="literal">null</span> &amp;&amp; msg.target == <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">//msg.target==null表示这个Message是同步屏障，将会暂停执行队列中的同步消息，</span></span><br><span class="line">                <span class="comment">//异步消息不受同步屏障的影响，所以找到下一个异步消息</span></span><br><span class="line">                <span class="keyword">do</span> &#123;</span><br><span class="line">                    prevMsg = msg;</span><br><span class="line">                    msg = msg.next;</span><br><span class="line">                &#125; <span class="keyword">while</span> (msg != <span class="literal">null</span> &amp;&amp; !msg.isAsynchronous());</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (msg != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (now &lt; msg.when) &#123;</span><br><span class="line">                    <span class="comment">//下个消息还没有到执行时间，因此计算出需要阻塞等待的时间，即阻塞等待的超时时间</span></span><br><span class="line">                    nextPollTimeoutMillis = (<span class="type">int</span>) Math.min(msg.when - now, Integer.MAX_VALUE);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">// Got a message.</span></span><br><span class="line">                    mBlocked = <span class="literal">false</span>;</span><br><span class="line">                    <span class="keyword">if</span> (prevMsg != <span class="literal">null</span>) &#123;</span><br><span class="line">                        prevMsg.next = msg.next;</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        mMessages = msg.next;</span><br><span class="line">                    &#125;</span><br><span class="line">                    msg.next = <span class="literal">null</span>;</span><br><span class="line">                    <span class="keyword">if</span> (DEBUG) Log.v(TAG, <span class="string">&quot;Returning message: &quot;</span> + msg);</span><br><span class="line">                    msg.markInUse();</span><br><span class="line">                    <span class="keyword">return</span> msg;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// No more messages.</span></span><br><span class="line">                nextPollTimeoutMillis = -<span class="number">1</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Process the quit message now that all pending messages have been handled.</span></span><br><span class="line">            <span class="keyword">if</span> (mQuitting) &#123;</span><br><span class="line">                dispose();</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// If first time idle, then get the number of idlers to run.</span></span><br><span class="line">            <span class="comment">// Idle handles only run if the queue is empty or if the first message</span></span><br><span class="line">            <span class="comment">// in the queue (possibly a barrier) is due to be handled in the future.</span></span><br><span class="line">            <span class="keyword">if</span> (pendingIdleHandlerCount &lt; <span class="number">0</span></span><br><span class="line">                    &amp;&amp; (mMessages == <span class="literal">null</span> || now &lt; mMessages.when)) &#123;</span><br><span class="line">                pendingIdleHandlerCount = mIdleHandlers.size();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (pendingIdleHandlerCount &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="comment">// No idle handlers to run.  Loop and wait some more.</span></span><br><span class="line">                mBlocked = <span class="literal">true</span>;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (mPendingIdleHandlers == <span class="literal">null</span>) &#123;</span><br><span class="line">                mPendingIdleHandlers = <span class="keyword">new</span> <span class="title class_">IdleHandler</span>[Math.max(pendingIdleHandlerCount, <span class="number">4</span>)];</span><br><span class="line">            &#125;</span><br><span class="line">            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Run the idle handlers.</span></span><br><span class="line">        <span class="comment">// We only ever reach this code block during the first iteration.</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; pendingIdleHandlerCount; i++) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="type">IdleHandler</span> <span class="variable">idler</span> <span class="operator">=</span> mPendingIdleHandlers[i];</span><br><span class="line">            mPendingIdleHandlers[i] = <span class="literal">null</span>; <span class="comment">// release the reference to the handler</span></span><br><span class="line"></span><br><span class="line">            <span class="type">boolean</span> <span class="variable">keep</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                keep = idler.queueIdle();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">                Log.wtf(TAG, <span class="string">&quot;IdleHandler threw exception&quot;</span>, t);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (!keep) &#123;</span><br><span class="line">                <span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">                    mIdleHandlers.remove(idler);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Reset the idle handler count to 0 so we do not run them again.</span></span><br><span class="line">        pendingIdleHandlerCount = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// While calling an idle handler, a new message could have been delivered</span></span><br><span class="line">        <span class="comment">// so go back and look again for a pending message without waiting.</span></span><br><span class="line">        nextPollTimeoutMillis = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="IdleHandler"><a href="#IdleHandler" class="headerlink" title="IdleHandler"></a>IdleHandler</h2><p>当消息队列中没有消息，消息循环将要去阻塞等待新消息的时候会执行IdleHandler。IdleHandler使用方法如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Looper.myLooper().getQueue().addIdleHandler(<span class="keyword">new</span> <span class="title class_">MessageQueue</span>.IdleHandler() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">queueIdle</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">//do something</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    <span class="comment">//返回false表示任务只执行一次，任务完成后将会被移除任务；</span></span><br><span class="line">    <span class="comment">//返回true表示下次消息循环将要阻塞时还会执行这个任务;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<h2 id="消息阻塞等待的底层实现"><a href="#消息阻塞等待的底层实现" class="headerlink" title="消息阻塞等待的底层实现"></a>消息阻塞等待的底层实现</h2><p>当消息队列中没有消息，或者消息的执行时间还没有到，消息队列的执行线程会进入阻塞等待状态。在MessageQueue.next()中通过调用<code>nativePollOnce</code>方法进行阻塞等待。nativePollOnce()方法定义如下，是一个native函数：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title function_">nativePollOnce</span><span class="params">(<span class="type">long</span> ptr, <span class="type">int</span> timeoutMillis)</span>; <span class="comment">/*non-static for callbacks*/</span></span><br></pre></td></tr></table></figure>

<ul>
<li>第一个参数<code>ptr</code>是native层C++ NativeMessageQueue对象的指针。</li>
<li>第二个参数<code>timeoutMillis</code>是阻塞等待超时时间，当达到超时时间后，会自动唤醒。阻塞的超时时间就是下个消息的执行时间减去当前系统时间得到的时间差。如果消息队列为空，则超时时间会传入-1，会一直阻塞，直到新消息插入后唤醒。</li>
</ul>
<p><code>nativePollOnce</code>的native实现代码如下：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//android-12.1.0_r27\frameworks\base\core\jni\android_os_MessageQueue.cpp</span></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">android_os_MessageQueue_nativePollOnce</span><span class="params">(JNIEnv* env, jobject obj,</span></span></span><br><span class="line"><span class="params"><span class="function">        jlong ptr, jint timeoutMillis)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//将java层传下来的ptr参数强转成NativeMessageQueue对象指针</span></span><br><span class="line">    NativeMessageQueue* nativeMessageQueue = <span class="built_in">reinterpret_cast</span>&lt;NativeMessageQueue*&gt;(ptr);</span><br><span class="line">    <span class="comment">//调用NativeMessageQueue#pollOnce方法</span></span><br><span class="line">    nativeMessageQueue-&gt;<span class="built_in">pollOnce</span>(env, obj, timeoutMillis);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">NativeMessageQueue::pollOnce</span><span class="params">(JNIEnv* env, jobject pollObj, <span class="type">int</span> timeoutMillis)</span> </span>&#123;</span><br><span class="line">    mPollEnv = env;</span><br><span class="line">    mPollObj = pollObj;</span><br><span class="line">    mLooper-&gt;<span class="built_in">pollOnce</span>(timeoutMillis); <span class="comment">//调用native层Looper对象的pollOnce方法</span></span><br><span class="line">    mPollObj = <span class="literal">NULL</span>;</span><br><span class="line">    mPollEnv = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (mExceptionObj) &#123;</span><br><span class="line">        env-&gt;<span class="built_in">Throw</span>(mExceptionObj);</span><br><span class="line">        env-&gt;<span class="built_in">DeleteLocalRef</span>(mExceptionObj);</span><br><span class="line">        mExceptionObj = <span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>native层的Looper函数在<code>system\core\libutils\Looper.cpp</code>文件中实现，native层的<code>Looper#pollOnce</code>方法实现代码很长，这里就不贴代码了，原理简要描述下：</p>
<p>native层的Looper类通过linux <a target="_blank" rel="noopener external nofollow noreferrer" href="https://man7.org/linux/man-pages/man2/eventfd.2.html">eventfd</a>和<a target="_blank" rel="noopener external nofollow noreferrer" href="https://man7.org/linux/man-pages/man7/epoll.7.html">epoll</a>两个机制来完成线程间通信。eventfd是用于事件通知机制的文件描述符，epoll则用于监控eventfd的I/O事件，两者结合可以实现事件的等待和通知。</p>
<p>构造时会通过linux函数<code>epoll_create1</code>创建一个epoll实例，并关联一个读写文件描述符，然后在pollOnce方法中，通过epoll_wait来监听这个文件描述符的I/O事件，收到事件或者超时后就会唤醒，否则线程就处于阻塞等待状态。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//android-12.1.0_r27\system\core\libutils\include\utils\Looper.h</span></span><br><span class="line">    <span class="comment">//unique_fd是android用于管理文件描述符的类，当离开作用域后文件会被自动关闭，在这里把它等同于文件描述符理解即可</span></span><br><span class="line">    android::base::unique_fd mWakeEventFd;  <span class="comment">//eventfd文件描述符</span></span><br><span class="line">    android::base::unique_fd mEpollFd; <span class="comment">//创建epoll实例后返回的文件描述符</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//android-12.1.0_r27\system\core\libutils\Looper.cpp</span></span><br><span class="line">Looper::<span class="built_in">Looper</span>(<span class="type">bool</span> allowNonCallbacks)</span><br><span class="line">    : <span class="built_in">mAllowNonCallbacks</span>(allowNonCallbacks),</span><br><span class="line">      <span class="built_in">mSendingMessage</span>(<span class="literal">false</span>),</span><br><span class="line">      <span class="built_in">mPolling</span>(<span class="literal">false</span>),</span><br><span class="line">      <span class="built_in">mEpollRebuildRequired</span>(<span class="literal">false</span>),</span><br><span class="line">      <span class="built_in">mNextRequestSeq</span>(<span class="number">0</span>),</span><br><span class="line">      <span class="built_in">mResponseIndex</span>(<span class="number">0</span>),</span><br><span class="line">      <span class="built_in">mNextMessageUptime</span>(LLONG_MAX) &#123;</span><br><span class="line">    <span class="comment">//调用eventfd系统函数创建eventfd，函数返回一个文件描述符，然后赋值给mWakeEventFd</span></span><br><span class="line">    mWakeEventFd.<span class="built_in">reset</span>(<span class="built_in">eventfd</span>(<span class="number">0</span>, EFD_NONBLOCK | EFD_CLOEXEC));</span><br><span class="line">    <span class="built_in">LOG_ALWAYS_FATAL_IF</span>(mWakeEventFd.<span class="built_in">get</span>() &lt; <span class="number">0</span>, <span class="string">&quot;Could not make wake event fd: %s&quot;</span>, <span class="built_in">strerror</span>(errno));</span><br><span class="line"></span><br><span class="line">    AutoMutex _l(mLock);</span><br><span class="line">    <span class="built_in">rebuildEpollLocked</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Looper::rebuildEpollLocked</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    ...... <span class="comment">//代码省略</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//epoll_create1方法创建一个epoll实例，返回的文件描述符赋值给mEpollFd</span></span><br><span class="line">    mEpollFd.<span class="built_in">reset</span>(<span class="built_in">epoll_create1</span>(EPOLL_CLOEXEC));</span><br><span class="line">    <span class="built_in">LOG_ALWAYS_FATAL_IF</span>(mEpollFd &lt; <span class="number">0</span>, <span class="string">&quot;Could not create epoll instance: %s&quot;</span>, <span class="built_in">strerror</span>(errno));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">epoll_event</span> eventItem;</span><br><span class="line">    <span class="built_in">memset</span>(&amp; eventItem, <span class="number">0</span>, <span class="built_in">sizeof</span>(epoll_event)); <span class="comment">// zero out unused members of data field union</span></span><br><span class="line">    eventItem.events = EPOLLIN; <span class="comment">//设置eventfd为可读</span></span><br><span class="line">    eventItem.data.fd = mWakeEventFd.<span class="built_in">get</span>();</span><br><span class="line">    <span class="comment">//把eventfd文件描述符添加到epoll的监控列表中</span></span><br><span class="line">    <span class="type">int</span> result = <span class="built_in">epoll_ctl</span>(mEpollFd.<span class="built_in">get</span>(), EPOLL_CTL_ADD, mWakeEventFd.<span class="built_in">get</span>(), &amp;eventItem);</span><br><span class="line">    </span><br><span class="line">    ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面代码实现了堵塞等待，并设置超时事件：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//system\core\libutils\Looper.cpp文件的Looper::pollInner方法中</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">Looper::pollInner</span><span class="params">(<span class="type">int</span> timeoutMillis)</span> </span>&#123;</span><br><span class="line">    .......</span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">epoll_event</span> eventItems[EPOLL_MAX_EVENTS];</span><br><span class="line">    <span class="type">int</span> eventCount = <span class="built_in">epoll_wait</span>(mEpollFd.<span class="built_in">get</span>(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);</span><br><span class="line">    .......</span><br><span class="line">    <span class="comment">//因为epoll支持同时监控多个文件描述符，因此循环查找</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; eventCount; i++) &#123;</span><br><span class="line">        <span class="type">int</span> fd = eventItems[i].data.fd;</span><br><span class="line">        <span class="type">uint32_t</span> epollEvents = eventItems[i].events;</span><br><span class="line">        <span class="keyword">if</span> (fd == mWakeEventFd.<span class="built_in">get</span>()) &#123;</span><br><span class="line">            <span class="keyword">if</span> (epollEvents &amp; EPOLLIN) &#123;</span><br><span class="line">                <span class="built_in">awoken</span>();</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="built_in">ALOGW</span>(<span class="string">&quot;Ignoring unexpected epoll events 0x%x on wake event fd.&quot;</span>, epollEvents);</span><br><span class="line">            &#125;</span><br><span class="line">        ......</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Looper::awoken</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    ......</span><br><span class="line">    <span class="type">uint64_t</span> counter;</span><br><span class="line">    <span class="comment">//从eventfd文件中读取一个int内容</span></span><br><span class="line">    <span class="built_in">TEMP_FAILURE_RETRY</span>(<span class="built_in">read</span>(mWakeEventFd.<span class="built_in">get</span>(), &amp;counter, <span class="built_in">sizeof</span>(<span class="type">uint64_t</span>)));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>唤醒堵塞等待的线程：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">Looper::wake</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="type">uint64_t</span> inc = <span class="number">1</span>;</span><br><span class="line">    <span class="comment">//向eventfd文件描述符中写入一个int值</span></span><br><span class="line">    <span class="type">ssize_t</span> nWrite = <span class="built_in">TEMP_FAILURE_RETRY</span>(<span class="built_in">write</span>(mWakeEventFd.<span class="built_in">get</span>(), &amp;inc, <span class="built_in">sizeof</span>(<span class="type">uint64_t</span>)));</span><br><span class="line">    ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="同步屏障"><a href="#同步屏障" class="headerlink" title="同步屏障"></a>同步屏障</h2><p>同步屏障就是target为null的一个Message。当插入一个同步屏障时，都会伴随着再发送一个异步消息。消息循环的处理中，在遇到同步屏障后，就不会再处理同步消息，异步消息则不受影响。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//frameworks\base\core\java\android\os\MessageQueue.java</span></span><br><span class="line">    Message <span class="title function_">next</span><span class="params">()</span> &#123;</span><br><span class="line">        ......</span><br><span class="line">        <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">            ......</span><br><span class="line">            nativePollOnce(ptr, nextPollTimeoutMillis);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">synchronized</span> (<span class="built_in">this</span>) &#123;</span><br><span class="line">                <span class="comment">// Try to retrieve the next message.  Return if found.</span></span><br><span class="line">                <span class="keyword">final</span> <span class="type">long</span> <span class="variable">now</span> <span class="operator">=</span> SystemClock.uptimeMillis();</span><br><span class="line">                <span class="type">Message</span> <span class="variable">prevMsg</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">                <span class="type">Message</span> <span class="variable">msg</span> <span class="operator">=</span> mMessages;</span><br><span class="line">                <span class="keyword">if</span> (msg != <span class="literal">null</span> &amp;&amp; msg.target == <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="comment">// Stalled by a barrier.  Find the next asynchronous message in the queue.</span></span><br><span class="line">                    <span class="keyword">do</span> &#123;</span><br><span class="line">                        prevMsg = msg;</span><br><span class="line">                        msg = msg.next;</span><br><span class="line">                    &#125; <span class="keyword">while</span> (msg != <span class="literal">null</span> &amp;&amp; !msg.isAsynchronous());</span><br><span class="line">                &#125;</span><br><span class="line">                ......</span><br></pre></td></tr></table></figure>

<p>在UI渲染流程中，在<code>ViewRootImpl#scheduleTraversals</code>是会首先插入同步屏障，然后调用<code>Choreographer</code>发送一个异步消息。这个异步消息中就会执行UI渲染的三大流程。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> <span class="title function_">scheduleTraversals</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (!mTraversalScheduled) &#123;</span><br><span class="line">        mTraversalScheduled = <span class="literal">true</span>;</span><br><span class="line">        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();</span><br><span class="line">        mChoreographer.postCallback(</span><br><span class="line">                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, <span class="literal">null</span>);</span><br><span class="line">        notifyRendererOfFramePending();</span><br><span class="line">        pokeDrawLockIfNeeded();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Android/" rel="tag"># Android</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/posts/c7038aa0.html" rel="prev" title="Java 公平锁和非公平锁">
                  <i class="fa fa-angle-left"></i> Java 公平锁和非公平锁
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/posts/faedbb97.html" rel="next" title="LeakCanary源码详解">
                  LeakCanary源码详解 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 
    <span itemprop="copyrightYear">2024</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">Jason</span>
  </div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener external nofollow noreferrer" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/pisces/" rel="noopener external nofollow noreferrer" target="_blank">NexT.Pisces</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.24/fancybox/fancybox.umd.js" integrity="sha256-oyhjPiYRWGXaAt+ny/mTMWOnN1GBoZDUQnzzgC7FRI4=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>


  <script class="next-config" data-name="mermaid" type="application/json">{"enable":true,"theme":{"light":"default","dark":"dark"},"js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.5.0/mermaid.min.js","integrity":"sha256-K7oJiQlDulzl24ZUFOywuYme1JqBBvQzK6m8qHjt9Gk="}}</script>
  <script type="module" src="/js/zenuml-definition-074a43fa.js"></script>
  <script type="module" src="/js/mermaid-zenuml.esm.min.mjs"></script>
  <script src="/js/third-party/tags/mermaid.js"></script>


  <script src="/js/third-party/fancybox.js"></script>



  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>



</body>
</html>
